<?php
/* Constant Vars like html doctype etc */
Class site {
/* Variable declarations */
	public $head;
	public $foot;
	public $navigation;
	public $left;
	public $right;
	public $content;
	public $output;
	public $page_id;
	public $cache;
	public $html;
	var $fs_cache=true;
	public $write_fs_cache;
	public function __construct() {
     $this->site_data();
	 $this->setupPage($_GET['_q']);
  	 // get the shit from the cache key in the PAGE document
	  $this->admin_group=$this->getAdminGroup();
	 if($this->page_settings['cache']==1) {
		$this->cache=true; 
	 
	 } else {
		$this->cache=false; 
	 	//echo("Not caching.");
	 }
	 if(!empty($_GET['q'])) {
		$this->cache=false;
	 } 
	if(count($this->page_settings['groups'])>=1 && !in_array($this->admin_group,$_SESSION['groups'])) {
		$this->cache=false; 
	 }
	 $this->CheckCache();
	 $this->buildTheme();
	 $this->buildHead();	
	 
	
	 
	
	 
	 if(count($this->page_settings['groups'])>=1 && !in_array($this->admin_group,$_SESSION['groups'])) {
		 foreach($this->page_settings['groups'] as $g) {
			
			if(!in_array($g,$_SESSION['groups'])) {
				$op="<h2>You do not have access to do that.</h2>";
			}
		 
		 	$this->setContent($op);
		 
	 }
	
		 
	 } else {
	  $this->buildNavigation();
	 
	 if($this->page_settings['is_blog']==1 || $this->page_settings['is_blog_post']==1) {
	 	if(!empty($this->page_settings['blog_post_id'])) {
			$this->buildBlogPost();
		} else {
			$this->buildBlogContent();
		}
	 
	 } else {
		$this->buildContent(); 
	 }
	  
	 }
    $this->footerNav();	
	}
	public function __destruct() {
		
	}
	public function CheckCache() {
		
		
		if($this->cache) {
		
		
		if(!$this->fs_cache) {
		$mc = new Memcached();
		$mc->addServer('localhost', 11211);
		$cachekey=DATABASE.'cached_page_'.$this->page_id;		
		$j=$mc->get($cachekey);
			if(	strlen($j)>=2	) {
				
				exit($j);
				}
		
			} else {

				$this->cache_page=$_SERVER['DOCUMENT_ROOT'].'/cache/'.(string)$this->page_id.'.html';
					//echo("ATTEMPTING READING FROM FS CACHE");
					if(file_exists($this->cache_page)) {
						$this->write_fs_cache=false;
						
						//$fp = fopen($this->cache_page, 'rb');
						//fpassthru($fp);	
						readfile($this->cache_page);
						exit();	
				} else {
						$this->write_fs_cache=true;	
				}
			}
		}
	}
	function getAdminGroup() {
		$data=new database();
		$data->db(DATABASE)->collection('groups');
		$data->criteria(array('name'=>'Administrators'));
		$row=$data->findOne();
		return (string)$row['_id'];	
	}
	public function setHtml($html) {
		// this is really the caching mech which will get aptly renamed in future versions
		if(!$this->fs_cache) {
		$mc = new Memcached();
		$mc->addServer('localhost', 11211);
		$cachekey=DATABASE.'cached_page_'.$this->page_id;			
		$mc->set($cachekey, $html,  86400);
		} else {
		file_put_contents($this->cache_page,$html);	
		unset($this->cache_page);
		}
		
		
		
		//file_put_contents($site->cache_page,$content."OS Cache Read");

			
		
	}
	protected function site_data() {
		$data=new database;
		$data->db(DATABASE)->collection('settings');
		$data->criteria(array('url'=>array('$exists'=>true)));
		//$data->cache(true)->cachekey(DATABASE.'.site');
		$row=$data->findOne();
		$data->close();
		$this->settings=$row;
		return $this;	
	}
	public function setHead($head) {
		$this->head[]=$head;
	return $this;	
	}
	
	
	public function setupPage($url) {
		//print_r($_GET);
		$uri=explode("/",$_GET['uri']);
		
		$url=(empty($url)) ? '/' : $url;
		$data=new database;
		$data->db(DATABASE)->collection('pages');
		if(is_numeric($uri[0])) {
		$data->criteria(array('post_id'=>intval($uri[0])));
		} else {
		$data->criteria(array('url'=>$url));	
		}
		
		$row=$data->findOne();
		//print_r($row);
		$data->close();
		$this->page_id=(string)$row['_id'];
		$this->page_settings=$row;
		if($this->page_settings['is_blog']==1 || $this->page_settings['is_blog_post']==1) {
			if(!empty($_GET['uri'])) {
				$u=explode("/",$_GET['uri']);
				$blog_id=$u[0];
				$this->page_settings['blog_post_id']=$blog_id;	
			}
		}
	
		
		
		return $this;	
	}
	public function buildTheme() {
		$data=new database;
		$data->db(DATABASE)->collection('settings');
		$data->criteria(array('current_theme'=>array('$exists'=>true)));
		$data->cache(true)->cachekey(DATABASE.'.current_theme');
		$row=$data->findOne();
		$data->close();
		$this->theme=$row;	
		return $this;
	}
	public function setFoot($foot) {
		$this->foot[]=$foot;
		return $this;	
	
	}
	public function setNavigation($element) {
		$this->navigation[$element['id']]=$element;
		return $this;	
	
	}
	
	public function setContent($content) {
		$this->content[]=$content;
		return $this;	

	}
	public function setLeft($left) {
		$this->left[]=$left;
		return $this;	
	
	}
	public function setRight($right) {
		$this->right[]=$right;
		return $this;	
	
	}

	public function head() {
		$this->output(implode("\r\n",$this->head));
		return $this;
	}
	public function foot() {
		$this->output(implode("\r\n",$this->foot));
		return $this;
	}
	public function navigation() {
		$this->output(implode("\r\n",$this->navigation));
		return $this;	
	}
	public function content() {
		$this->output(implode("\r\n",$this->content));
		return $this;	
	}
	public function left() {
		$this->output(implode("\r\n",$this->left));
		return $this;	
	}
	public function right() {
		$this->output(implode("\r\n",$this->right));
		return $this;	
	}
	public function getPageMeta() {
		$data=new database;
		$data->db(DATABASE)->collection('meta_data');
		$data->criteria(array('page_id'=>$this->page_id));
		//$data->cache(true)->cachekey(DATABASE.'meta_'.$page_id);
		$row=$data->findOne();
		$data->close();
		return $row;	
	}
	public function output($string) {
/* Shit needs parsing here */
		// when it gets parsed extract the module id and set the current module ID to it...
		$string=$this->parseForModules($string);
		$string=$this->parseForForms($string);
		echo($string);
		return $this;
	}
	public function getNavigationParents() {
		$data=new database;
		$data->db(DATABASE)->collection('pages');
		//$data->slice(true)->fields(array('game_plays'=> array('$slice' => 2)));
		$data->criteria(array('is_parent'=>intval(1),'active'=>intval(1),'include_in_nav'=>intval(1)))->sort(array('order'=>1)); 
		//$data->cache(true)->cachekey(DATABASE.'.navigation');
		$rows=$data->findNl();
	//	print_r($rows);
		
		$this->num_parents=$rows['num_results'];
		foreach($rows['results'] as $row) {
			//echo();
			$selected=($row['url']==CURRENT_PAGE) ? true : false;
			$id=(string)$row['_id'];
		//	echo("$id <hr />");
			//var_dump($children);
		//	echo("<pre>Adding $row[url] to navigation ($id)\n");
			$this->setNavigation(array('id'=>$id,'text'=>$row['text'],'url'=>$row['url'],'current'=>$selected)); // inject the children into it with the function..
		//	echo("Seeking children for $row[url] ($id) \n");
			$children=$this->getNavigationChildren($id);
		//	echo("</pre>");	
		}
	//	echo("<pre>");
	//	print_r($this->navigation);
	//	echo("</pre>");
	return $this;	
	}
	public function getNavigationChildren($id) {
		$data=new database;
		$data->db(DATABASE)->collection('pages');
		$data->criteria(array('active'=>intval(1),'is_parent'=>intval(0),'parent'=>$id,'include_in_nav'=>intval(1)))->sort(array('order'=>1));
		$parent=$id;
		$rows=$data->findNl();
		if($rows['num_results']>=1) {
			foreach($rows['results'] as $row) {
				$selected=($row['url']==CURRENT_PAGE) ? true : false;
				if(!$this->navigation[$row['parent']]['current']) {
					$this->navigation[$row['parent']]['current']=$selected;
				}
				$id=(string)$row['_id'];
				//$children=$this->getNavigationChildren((string)$row['_id']); // bug here somewhere and I cant work out why
				$output[]=array('id'=>(string)$row['_id'],'text'=>$row['text'],'url'=>$row['url'],'current'=>$selected,'children'=>$children);
				
			}
			$this->navigation[$parent]['children']=$output;
			unset($output);
		}
	return $this;	
	}
	public function unsetNavigation() {
		unset($this->navigation);
		return $this;	
	}

	public function buildNavigation() {
		$this->getNavigationParents();
	$p=1;
	$t=$this->num_parents;
			foreach($this->navigation as $key=>$navigation) {
				$has_children=(is_array($navigation['children']) && count($navigation['children']>=1)) ? true : false;
				
				$selected=($navigation['current']==true) ? 'navigation-item navigation-selected' : 'navigation-item';
				$c_arrow=($has_children==true) ? '<span class="has_sub">&nbsp;&nbsp;&nbsp;&nbsp;</span>' : '';
				$n_last=($p==$t) ? ' nav-last' : '';
				if(!empty($navigation['id'])) {
				$output[]='<li class="nav-item'.$n_last.'"><a id="nav-'.(string)$navigation['id'].'" href="'.$navigation['url'].'" class="'.$selected.'">'.$navigation['text'].'</a>';
				if($has_children) { 
					$output[]='<ul class="menu-sub" style="display:none;">';
						foreach($navigation['children'] as $nav_child) {
							$s=($nav_child['current']==true) ? 'navigation-child-selected' : '';
							$na=($nav_child['current']==true) ? ' nav-child-selected' : '';
							
							$output[]='<li class="'.$s.'"><a href="'.$nav_child['url'].'" id="nav-child-'.(string)$nav_child['id'].'" class="navigation-child'.$na.'">'.$nav_child['text'].'</a></li>';
						}
					$output[]='</ul>';
				}
				$output[]='</li>';				
			$p++;
							} // update this shit to just not add it or work out why it's even adding it in the first place...

			}
			
			$this->unsetNavigation()->setNavigation(implode("\r\n",$output));
			
		}
		function addToNavigation($content) {
			$this->navigation[]=$content;		
		}
		function buildBlogPost() {
		
		$page_id=$this->page_id;
		$data=new database;
		
		$data->db(DATABASE)->collection('pages');
		$data->criteria(array('post_id'=>intval($this->page_settings['blog_post_id'])));
		$row=$data->findOne();
			
				$this->setContent('<div id="content-'.(string)$row['_id'].'" class="page-content blog-post">
				<span class="blog-date">'.date("d/m/y \@ G:i",$row['timestamp']).' GMT by '.$row['author'].'</span>
				<p>'.$row['content'].'</p></div><div class="separator"></div>');	
			
		
		return $this;
		
		}
		function captcha() {
			
		
		
			
		}
		
		
		function buildBlogContent() {
		$page_id=$this->page_id;
		$data=new database;
		
		// limit and skip
		$page_number=($_GET['page']<=0) ? 1 : $_GET['page'];
		$skip = intval((10 * ($page_number - 1)));

		$data->db(DATABASE)->collection('pages');
		$data->criteria(array('is_blog_post'=>intval(1),'active'=>intval(1)))->skip($skip)->limit(10)->sort(array('timestamp'=>-1));//'active'=>intval(1),
		// cache in memcache eventually....		
		//$this->truncate($text, $length, $suffix = '&hellip;', $isHTML = true);
			$rows=$data->find();
			$num_pages=ceil(($row['num_results']/10));
			$max_pages=4;
/*
$this->setContent('<div id="recent-posts"><h2 style="margin-bottom:8px;">Recent posts</h2>');
$this->setContent('<ul>');
for($o=1;$o<=10;$o++) {
	$this->setContent('<li>Post '.$o.'</li>');	
}
$this->setContent('</ul>');
$this->setContent('</div>');
*/
			foreach($rows['results'] as $row) {
				
				$truncate_ending='	<a class="blog-read-more" href="'.$row['url'].'">read more..</a>';
				unset($tags);
				if(count($row['tags'])>=1) {
					foreach($row['tags'] as $tag) {
						$tags[]='<a class="result" href="'.$row['url'].'?q='.urlencode(strtolower($tag)).'">'.$tag.'</a>';	
					}
				$t='<br /><label>Tags:</label><br />'.implode(", ",$tags);
				}
			$content=preg_replace('/\[(.*?)\](.*?)\[\/(.*?)\]/im','',$row['content']);

				$this->setContent('<div id="content-'.(string)$row['_id'].'" class="page-content blog-content">
				<a href="'.$row['url'].'"><h3 class="blog-post-heading">'.$row['heading'].'</h3></a>
				<span class="blog-date">'.date("d/m/y \@ G:i",$row['timestamp']).' GMT by '.$row['author'].'</span>
				<p>'.$this->truncate($content,800).' '.$truncate_ending.'<br />'.$t.'</p></div><div class="separator"></div>');	
			}
			$this->setContent('<div class="clearfix"></div>');
			$pagination=$this->pagination($page_number,$num_pages,$max_pages,"?page=$page_number");
			if(!empty($pagination)) {
				$this->setContent('<div style="text-align:right;padding-top:1em;padding-bottom:1em;">'.$pagination.'</div>');
			}
		return $this;
		}
		public function footerNav() {
			$data=new database();
			$data->db(DATABASE)->collection('pages');
			$data->criteria(array('include_in_nav'=>intval(1),'is_parent'=>intval(1),'active'=>intval(1)))->sort(array('order'=>1));
			$rows=$data->findNl();
			$data->close();
			$this->footNav='';
			foreach($rows['results'] as $key=>$navigation) {
				
			$this->footNav[]=array('text'=>$navigation['text'],'url'=>$navigation['url']);		
				
			}
			
			
			return $this;
		}
		
		public function buildContent() {
		
		$page_id=$this->page_id;
		$data=new database;
		
		$data->db(DATABASE)->collection('pages');
		$data->criteria(array('_id'=>new MongoId($this->page_id)));
		$row=$data->findOne();	
		$this->setContent('<div id="content-'.(string)$row['_id'].'" class="page-content">'.$row['content'].'</div>');
		$this->setContent('<div class="clearfix"></div>');	
		return $this;
		}
		public function buildHead() {
			$this->setHead(DOCTYPE)->setHead(HTML_XMLNS)->setHead('<head>')->setHead(CONTENT_TYPE);
			$page=$this->getPageInformation($this->page_id);
						$this->setHead('<title>'.$page['meta']['title'].'</title>');

			$this->setHead('<meta name="description" content="'.$page['meta']['description'].'" />');
			$this->setHead('<meta name="keywords" content="'.$page['meta']['keywords'].'" />');
			if(!empty($page['meta']['custom'])) {
				$this->setHead($page['meta']['custom']);
			}
			$this->setHead('<link rel="stylesheet" href="'.$this->settings['url'].'/bundle/bundle.css" />');//change to bundle later
			$this->setHead('<link rel="shortcut icon" href="'.$this->settings['url'].'/favicon.ico?v=1" />');
 			$this->setHead('<script async src="'.$this->settings['url'].'/bundle/bundle.js"></script>');
			$this->setHead('</head>');
			//
 
			return $this;
		}
		function  getPageInformation($id) {
			$data=new database;
			$data->db(DATABASE)->collection('pages');
			$data->criteria(array('_id'=>new MongoId($id)));
		return $data->findOne();
		}
		function getSnippet($id) {
			$data=new database;
			$data->db(DATABASE)->collection('content');
			$data->criteria(array('page_id'=>$id,'type'=>'text'));
			$data->sort(array('order'=>1))->limit(1);
			$row=$data->find();
			$data->close();
			return $row;
		}
		public function setSearchTerms($terms='') {
			$terms=str_replace(',','|',$terms);
			$terms=str_replace(' ','|',$terms);
			
			$this->searchTerms=strtolower($terms);
			return $this;
		}
		public function setSkipNum($skip='') {
			$this->skip=(empty($skip)) ? 0 : $skip; 
			return $this;
		}
		public function search() {
			$data=new database();
			$data->db(DATABASE)->collection('search_index');
			$data->criteria(array('tags'=>new MongoRegex('/'.$this->searchTerms.'/')));
			$data->sort(array('tags' => 0))->limit(10)->skip($this->skip);
			$rows=$data->find();
			$data->close();
			return $rows;
		}
		public function pagination($page_number,$num_pages,$max_pages,$path,$extra='',$class='pagination') {
if($page_number==0) {

$page_number=1;	
}
$_pn=$page_number;

	if($page_number <=1) {
		$previous='';
	} else { 
		
		$paff=str_replace("page=".$_pn,"page=".($page_number-1),$path);
		
		$previous='<a rel="'.($page_number-1).'" href="'.$paff.$extra.'" class="'.$class.' tip" title="Goto Previous Page">Prev</a>'; 
	}
	
	if( ($page_number >= $num_pages) && ($page_number >= $max_pages) ) {
		$next="";
	} else {
				$paff=str_replace("page=".$_pn,"page=".($page_number+1),$path);

		$next='<a rel="'.($page_number+1).'" href="'.$paff.$extra.'" class="'.$class.' tip" title="Goto Next Nage">Next</a>';
	}

$pn=$page_number;
	if( ($page_number-($max_pages/2)) <=1  ) {
	for($m=1;$m<$page_number;$m++)
		{
					$paff=str_replace("page=".$_pn,"page=".($m),$path);

			$left.='<a rel="'.$m.'" class="'.$class.' tip" href="'.$paff.$extra.'" title="Goto Page '.$m.'">'.$m.'</a>';
		}
	unset($m);
	} else {
	
	for($m=$page_number-ceil(($max_pages/2));$m<$page_number;$m++)
		{
			$paff=str_replace("page=".$_pn,"page=".($m),$path);
			$left.='<a rel="'.$m.'" class="'.$class.' tip" href="'.$paff.$extra.'" title="Goto Page '.$m.'">'.$m.'</a>';
		}
	
	
	}
	if( ($page_number > 1) && ($page_number-($max_pages/2) >= 1)) {
	
		if(($page_number-($max_pages/2) >= 1)) {
	} else { 	
	}
	}
	if( (($page_number + $max_pages) < $num_pages)) {
	
	
	}
	if(($page_number > 1)) {
		$paff=str_replace("page=".$_pn,"page=1",$path);
		$first='<a rel="1" href="'.$paff.$extra.'" title="Goto First Page" class="'.$class.' tip">&laquo;&laquo;</a>';
	}
	if(($page_number!=$num_pages)) {
		
		$paff=str_replace("page=".$_pn,"page=".($num_pages),$path);
		$last='<a rel="'.$num_pages.'" class="'.$class.' tip" href="'.$paff.$extra.'" title="Goto Last Page">&raquo;&raquo;</a>';
	}
	for($i=$page_number;$i<=$num_pages;$i++) {
		if( $x<($max_pages)) {
			if($page_number==0) { $page_number=1; }
			if($i!=$page_number) {
				
				if($i==0) {
				$right.="";
				} else {
				$paff=str_replace("page=".$_pn,"page=".($i),$path);
				$right.='<a rel="'.$i.'" class="'.$class.' tip" href="'.$paff.$extra.'" title="Goto Page '.$i.'">'.$i.'</a>';
				}
			} else {
				
				$paff=str_replace("page=".$_pn,"page=".($i),$path);
				$right.='<a href="'.$paff.$extra.'" class="'.$class.' '.$class.'-selected" rel="'.$i.'">'.$i.'</a>';

			}
		}
			$x++;

	}
	if($page_number==$num_pages) {
	$next="";
	}
	
if($num_pages>1) {
return $pageOutput.$first.$previous.$concatLeft.$left.$right.$concatRight.$next.$last;
	} else {
		return "";
	}
}
		function parseForModules($str) {
			preg_match_all('/\[module\](.*?)\[\/module\]/im',$str,$matches);
			if(count($matches[0])<=0) {
				return $str;	
			}
			$module= new module();
			
			foreach($matches[0] as $key=>$val) {
				$find=$matches[0][$key];
				$replace=$module->parse($matches[1][$key]);
				$output=str_replace($find,$replace,$str);
			}
			return $output; // return it back to the output script..
		}
		function parseForForms($str) {
			$a='<textarea>'.$str.'</textarea>';
			
			preg_match_all('/\[form\](.*?)\[\/form\]/im',$str,$matches);
			
			if(count($matches[0])<=0) {
				return $str;	
			}
			$form= new form();
			foreach($matches[0] as $key=>$val) {
				
				$find=$matches[0][$key];
				$replace=$form->include_form($matches[1][$key]);
				$output=str_replace($find,$replace,$str);
			}
		return $output;
		}
		
		function truncate($text, $length = 100, $ending = '...', $exact = false, $considerHtml = true) {
	
	if ($considerHtml) {
		// if the plain text is shorter than the maximum length, return the whole text
		if (strlen(preg_replace('/<.*?>/', '', $text)) <= $length) {
			return $text;
		}
		// splits all html-tags to scanable lines
		preg_match_all('/(<.+?>)?([^<>]*)/s', $text, $lines, PREG_SET_ORDER);
		$total_length = strlen($ending);
		$open_tags = array();
		$truncate = '';
		foreach ($lines as $line_matchings) {
			// if there is any html-tag in this line, handle it and add it (uncounted) to the output
			if (!empty($line_matchings[1])) {
				// if it's an "empty element" with or without xhtml-conform closing slash
				if (preg_match('/^<(\s*.+?\/\s*|\s*(img|br|input|hr|area|base|basefont|col|frame|isindex|link|meta|param)(\s.+?)?)>$/is', $line_matchings[1])) {
					// do nothing
				// if tag is a closing tag
				} else if (preg_match('/^<\s*\/([^\s]+?)\s*>$/s', $line_matchings[1], $tag_matchings)) {
					// delete tag from $open_tags list
					$pos = array_search($tag_matchings[1], $open_tags);
					if ($pos !== false) {
					unset($open_tags[$pos]);
					}
				// if tag is an opening tag
				} else if (preg_match('/^<\s*([^\s>!]+).*?>$/s', $line_matchings[1], $tag_matchings)) {
					// add tag to the beginning of $open_tags list
					array_unshift($open_tags, strtolower($tag_matchings[1]));
				}
				// add html-tag to $truncate'd text
				$truncate .= $line_matchings[1];
			}
			// calculate the length of the plain text part of the line; handle entities as one character
			$content_length = strlen(preg_replace('/&[0-9a-z]{2,8};|&#[0-9]{1,7};|[0-9a-f]{1,6};/i', ' ', $line_matchings[2]));
			if ($total_length+$content_length> $length) {
				// the number of characters which are left
				$left = $length - $total_length;
				$entities_length = 0;
				// search for html entities
				if (preg_match_all('/&[0-9a-z]{2,8};|&#[0-9]{1,7};|[0-9a-f]{1,6};/i', $line_matchings[2], $entities, PREG_OFFSET_CAPTURE)) {
					// calculate the real length of all entities in the legal range
					foreach ($entities[0] as $entity) {
						if ($entity[1]+1-$entities_length <= $left) {
							$left--;
							$entities_length += strlen($entity[0]);
						} else {
							// no more characters left
							break;
						}
					}
				}
				$truncate .= substr($line_matchings[2], 0, $left+$entities_length);
				// maximum lenght is reached, so get off the loop
				break;
			} else {
				$truncate .= $line_matchings[2];
				$total_length += $content_length;
			}
			// if the maximum length is reached, get off the loop
			if($total_length>= $length) {
				break;
			}
		}
	} else {
		if (strlen($text) <= $length) {
			return $text;
		} else {
			$truncate = substr($text, 0, $length - strlen($ending));
		}
	}
	// if the words shouldn't be cut in the middle...
	if (!$exact) {
		// ...search the last occurance of a space...
		$spacepos = strrpos($truncate, ' ');
		if (isset($spacepos)) {
			// ...and cut the text in this position
			$truncate = substr($truncate, 0, $spacepos);
		}
	}
	// add the defined ending to the text
	$truncate .= $ending;
	if($considerHtml) {
		// close all unclosed html-tags
		foreach ($open_tags as $tag) {
			$truncate .= '</' . $tag . '>';
		}
	}
	return $truncate;
}

	//4e2e8f2743d932ad7b000000	
}
?>